<!DOCTYPE html>



  


<html class="theme-next mist use-motion" lang="zh-CN">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />







<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.3" rel="stylesheet" type="text/css" />


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=5.1.3">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=5.1.3">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=5.1.3">


  <link rel="mask-icon" href="/images/logo.svg?v=5.1.3" color="#222">





  <meta name="keywords" content="Hexo, NexT" />





  <link rel="alternate" href="/atom.xml" title="Likianta Blog" type="application/atom+xml" />






<meta name="description" content="1. 预先准备1.1. 先看一下最终效果图">
<meta property="og:type" content="article">
<meta property="og:title" content="06 Anykey用户数据的存储和加载SecuritySharedPreference">
<meta property="og:url" content="https://likianta.coding.me/2017/1203202855/index.html">
<meta property="og:site_name" content="Likianta Blog">
<meta property="og:description" content="1. 预先准备1.1. 先看一下最终效果图">
<meta property="og:locale" content="zh-CN">
<meta property="og:image" content="http://ozurciydg.bkt.clouddn.com/17-12-3/88634701.jpg">
<meta property="og:image" content="http://ozurciydg.bkt.clouddn.com/17-12-3/60282353.jpg">
<meta property="og:image" content="http://ozurciydg.bkt.clouddn.com/17-12-3/80000455.jpg">
<meta property="og:image" content="http://ozurciydg.bkt.clouddn.com/17-12-3/20508938.jpg">
<meta property="og:image" content="http://ozurciydg.bkt.clouddn.com/17-12-3/44311689.jpg">
<meta property="og:image" content="http://ozurciydg.bkt.clouddn.com/17-12-3/77953561.jpg">
<meta property="og:image" content="http://ozurciydg.bkt.clouddn.com/17-12-3/88634701.jpg">
<meta property="og:image" content="http://ozurciydg.bkt.clouddn.com/17-12-3/46262616.jpg">
<meta property="og:updated_time" content="2017-12-31T15:26:28.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="06 Anykey用户数据的存储和加载SecuritySharedPreference">
<meta name="twitter:description" content="1. 预先准备1.1. 先看一下最终效果图">
<meta name="twitter:image" content="http://ozurciydg.bkt.clouddn.com/17-12-3/88634701.jpg">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Mist',
    version: '5.1.3',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="https://likianta.coding.me/2017/1203202855/"/>





  <title>06 Anykey用户数据的存储和加载SecuritySharedPreference | Likianta Blog</title>
  








</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-CN">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">Likianta Blog</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle"></p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tutorials">
          <a href="/tags/tutorial-catalog/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            教程
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            归档
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            标签
          </a>
        </li>
      
        
        <li class="menu-item menu-item-about">
          <a href="/about/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br />
            
            关于
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="https://likianta.coding.me/2017/1203202855/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="Likianta">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="http://ozurciydg.bkt.clouddn.com/18-2-12/72826549.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Likianta Blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">06 Anykey用户数据的存储和加载SecuritySharedPreference</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2017-12-03T20:28:55+08:00">
                2017-12-03
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/passport-pandora/" itemprop="url" rel="index">
                    <span itemprop="name">从零开发Anykey</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">字数统计&#58;</span>
                
                <span title="字数统计">
                  9,546
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                
                <span title="阅读时长">
                  47
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <h1 id="1-预先准备"><a href="#1-预先准备" class="headerlink" title="1. 预先准备"></a>1. 预先准备</h1><h2 id="1-1-先看一下最终效果图"><a href="#1-1-先看一下最终效果图" class="headerlink" title="1.1. 先看一下最终效果图"></a>1.1. 先看一下最终效果图</h2><p><img src="http://ozurciydg.bkt.clouddn.com/17-12-3/88634701.jpg" alt=""></p>
<a id="more"></a>
<h2 id="1-2-确认默认启动界面仍是登录界面"><a href="#1-2-确认默认启动界面仍是登录界面" class="headerlink" title="1.2. 确认默认启动界面仍是登录界面"></a>1.2. 确认默认启动界面仍是登录界面</h2><p>下面的章节会先从登录逻辑的完整实现开始讲起。<br>有些同学在调试的过程中为了方便，在AndroidManifest中把默认启动项改成了MainActivity。所以请预先确认将启动项设置为LoginActivity（如图所示）：</p>
<p><img src="http://ozurciydg.bkt.clouddn.com/17-12-3/60282353.jpg" alt=""></p>
<font size="2" color="gray">（PS：换用了新的主题，具体可见：<a href="http://blog.csdn.net/likianta/article/details/78701481" target="_blank" rel="noopener">http://blog.csdn.net/likianta/article/details/78701481</a> ）</font>

<h2 id="1-3-创建LogUtil-java用来记录日志"><a href="#1-3-创建LogUtil-java用来记录日志" class="headerlink" title="1.3. 创建LogUtil.java用来记录日志"></a>1.3. 创建LogUtil.java用来记录日志</h2><p>由于在项目测试期间会留下大量的日志信息，会给将来项目的正式发布带来麻烦。所以现在开始编写一个LogUtil用来管理日志的输出与关闭，主要功能如下：</p>
<ol>
<li>使用方便，只传一个参量（String msg）即可</li>
<li>可以通过调节阀值来控制打印等级，甚至关闭所有打印</li>
</ol>
<p>代码如下（参考：LogUtil：郭霖《第一行代码 第二版》p464）：</p>
<p><code>LogUtil.java</code></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> android.util.Log;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Created by Likianta_DoDoRa on 2017/11/30 0030.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LogUtil</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 自制Log管理工具，通过设定level的等级，来显示自己想看的Log，而且只需要传入msg字段即可，tag统一为默认的“likianta_ddr”。</span></span><br><span class="line"><span class="comment">     * level设的越高，显示的信息就越危险。不过level设为NOTHING（=6）的时候，该Log工具将会关闭。因此在apk正式发布前，应把level调到NOTHING，从而把LogUtil关闭掉。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> VERBOSE = <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> DEBUG = <span class="number">2</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> INFO = <span class="number">3</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> WARN = <span class="number">4</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> ERROR = <span class="number">5</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> NOTHING = <span class="number">6</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String TAG = <span class="string">"likianta_ddr"</span>; <span class="comment">//你也可以更改为自己想要的TAG</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> level = VERBOSE;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">v</span><span class="params">(String msg)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (level &lt;= VERBOSE)&#123;</span><br><span class="line">            Log.d(TAG,msg);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">d</span><span class="params">(String msg)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (level &lt;= DEBUG)&#123;</span><br><span class="line">            Log.d(TAG,msg);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">i</span><span class="params">(String msg)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (level &lt;= INFO)&#123;</span><br><span class="line">            Log.d(TAG,msg);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">w</span><span class="params">(String msg)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (level &lt;= WARN)&#123;</span><br><span class="line">            Log.d(TAG,msg);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">e</span><span class="params">(String msg)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (level &lt;= ERROR)&#123;</span><br><span class="line">            Log.d(TAG,msg);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>使用方法：</p>
<ol>
<li><code>LogUtil.d(&quot;输入一些文字&quot;);</code></li>
<li>打开Logcat，在过滤器中输入自定义的TAG名称以查看日志信息</li>
</ol>
<h2 id="1-4-添加以下依赖库"><a href="#1-4-添加以下依赖库" class="headerlink" title="1.4. 添加以下依赖库"></a>1.4. 添加以下依赖库</h2><p>本章中新增的有：Glide（用于加载图片）、Glide-transformation（Glide增强工具）、Gson（用于处理Json数据）：</p>
<p><code>app:build.gradle</code></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">dependencies &#123;</span><br><span class="line">    ...</span><br><span class="line">    compile <span class="string">'me.relex:circleindicator:1.2.2'</span></span><br><span class="line">    compile <span class="string">'de.hdodenhof:circleimageview:2.2.0'</span></span><br><span class="line"></span><br><span class="line">    compile <span class="string">'com.github.bumptech.glide:glide:3.7.0'</span></span><br><span class="line">    compile <span class="string">'jp.wasabeef:glide-transformations:2.0.0'</span></span><br><span class="line">    compile <span class="string">'com.google.code.gson:gson:2.8.0'</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>配置完成注意点击“Sync Now”（后面的文章不再提醒此操作）。</p>
<p>下面开始正文。</p>
<hr>
<h1 id="2-使用SecuritySharedPreference完成登录的加-解密过程"><a href="#2-使用SecuritySharedPreference完成登录的加-解密过程" class="headerlink" title="2. 使用SecuritySharedPreference完成登录的加/解密过程"></a>2. 使用SecuritySharedPreference完成登录的加/解密过程</h1><h2 id="2-1-配置SecuritySharedPreference"><a href="#2-1-配置SecuritySharedPreference" class="headerlink" title="2.1. 配置SecuritySharedPreference"></a>2.1. 配置SecuritySharedPreference</h2><p>这里本来想用Github上的<a href="https://github.com/iamMehedi/Secured-Preference-Store" target="_blank" rel="noopener">SecuredPreferenceStore</a>项目，但是发现初始化函数会出错，并且EncrtyManager也无法正常使用，所以就放弃了。</p>
<p>后来使用@随便想个名字 的代码，功能和之前想用的SecuredPreferenceStore相同，并且支持旧数据的迁移，所以就完全照搬了：</p>
<p><strong>作者的博客地址：【Android安全】自带加密光环的SharedPreference - CSDN博客 <a href="http://blog.csdn.net/voidmain_123/article/details/53338393" target="_blank" rel="noopener">http://blog.csdn.net/voidmain_123/article/details/53338393</a> </strong></p>
<font>1. 新建<code>SecuritySharedPreference.java</code>（以下代码直接复制即可）：<br><br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> android.annotation.TargetApi;</span><br><span class="line"><span class="keyword">import</span> android.content.Context;</span><br><span class="line"><span class="keyword">import</span> android.content.SharedPreferences;</span><br><span class="line"><span class="keyword">import</span> android.os.Build;</span><br><span class="line"><span class="keyword">import</span> android.preference.PreferenceManager;</span><br><span class="line"><span class="keyword">import</span> android.support.annotation.Nullable;</span><br><span class="line"><span class="keyword">import</span> android.text.TextUtils;</span><br><span class="line"><span class="keyword">import</span> android.util.Log;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.HashSet;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 自动加密SharedPreference</span></span><br><span class="line"><span class="comment"> * Created by Max on 2016/11/23.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SecuritySharedPreference</span> <span class="keyword">implements</span> <span class="title">SharedPreferences</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">private</span> SharedPreferences mSharedPreferences;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String TAG = SecuritySharedPreference.class.getName();</span><br><span class="line">    <span class="keyword">private</span> Context mContext;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * constructor</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> context should be ApplicationContext not activity</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> name file name</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> mode context mode</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">SecuritySharedPreference</span><span class="params">(Context context, String name, <span class="keyword">int</span> mode)</span></span>&#123;</span><br><span class="line">        mContext = context;</span><br><span class="line">        <span class="keyword">if</span> (TextUtils.isEmpty(name))&#123;</span><br><span class="line">            mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            mSharedPreferences =  context.getSharedPreferences(name, mode);</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Map&lt;String, String&gt; <span class="title">getAll</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Map&lt;String, ?&gt; encryptMap = mSharedPreferences.getAll();</span><br><span class="line">        <span class="keyword">final</span> Map&lt;String, String&gt; decryptMap = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span> (Map.Entry&lt;String, ?&gt; entry : encryptMap.entrySet())&#123;</span><br><span class="line">            Object cipherText = entry.getValue();</span><br><span class="line">            <span class="keyword">if</span> (cipherText != <span class="keyword">null</span>)&#123;</span><br><span class="line">                decryptMap.put(entry.getKey(), entry.getValue().toString());</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> decryptMap;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * encrypt function</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> cipherText base64</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> String <span class="title">encryptPreference</span><span class="params">(String plainText)</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> EncryptUtil.getInstance(mContext).encrypt(plainText);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * decrypt function</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> plainText</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> String <span class="title">decryptPreference</span><span class="params">(String cipherText)</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> EncryptUtil.getInstance(mContext).decrypt(cipherText);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Nullable</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getString</span><span class="params">(String key, String defValue)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> String encryptValue = mSharedPreferences.getString(encryptPreference(key), <span class="keyword">null</span>);</span><br><span class="line">        <span class="keyword">return</span> encryptValue == <span class="keyword">null</span> ? defValue : decryptPreference(encryptValue);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Nullable</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Set&lt;String&gt; <span class="title">getStringSet</span><span class="params">(String key, Set&lt;String&gt; defValues)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> Set&lt;String&gt; encryptSet = mSharedPreferences.getStringSet(encryptPreference(key), <span class="keyword">null</span>);</span><br><span class="line">        <span class="keyword">if</span> (encryptSet == <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> defValues;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">final</span> Set&lt;String&gt; decryptSet = <span class="keyword">new</span> HashSet&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span> (String encryptValue : encryptSet)&#123;</span><br><span class="line">            decryptSet.add(decryptPreference(encryptValue));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> decryptSet;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getInt</span><span class="params">(String key, <span class="keyword">int</span> defValue)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> String encryptValue = mSharedPreferences.getString(encryptPreference(key), <span class="keyword">null</span>);</span><br><span class="line">        <span class="keyword">if</span> (encryptValue == <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> defValue;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> Integer.parseInt(decryptPreference(encryptValue));</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">long</span> <span class="title">getLong</span><span class="params">(String key, <span class="keyword">long</span> defValue)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> String encryptValue = mSharedPreferences.getString(encryptPreference(key), <span class="keyword">null</span>);</span><br><span class="line">        <span class="keyword">if</span> (encryptValue == <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> defValue;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> Long.parseLong(decryptPreference(encryptValue));</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">float</span> <span class="title">getFloat</span><span class="params">(String key, <span class="keyword">float</span> defValue)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> String encryptValue = mSharedPreferences.getString(encryptPreference(key), <span class="keyword">null</span>);</span><br><span class="line">        <span class="keyword">if</span> (encryptValue == <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> defValue;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> Float.parseFloat(decryptPreference(encryptValue));</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">getBoolean</span><span class="params">(String key, <span class="keyword">boolean</span> defValue)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">final</span> String encryptValue = mSharedPreferences.getString(encryptPreference(key), <span class="keyword">null</span>);</span><br><span class="line">        <span class="keyword">if</span> (encryptValue == <span class="keyword">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> defValue;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> Boolean.parseBoolean(decryptPreference(encryptValue));</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">contains</span><span class="params">(String key)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> mSharedPreferences.contains(encryptPreference(key));</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> SecurityEditor <span class="title">edit</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> SecurityEditor();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">registerOnSharedPreferenceChangeListener</span><span class="params">(OnSharedPreferenceChangeListener listener)</span> </span>&#123;</span><br><span class="line">        mSharedPreferences.registerOnSharedPreferenceChangeListener(listener);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">unregisterOnSharedPreferenceChangeListener</span><span class="params">(OnSharedPreferenceChangeListener listener)</span> </span>&#123;</span><br><span class="line">        mSharedPreferences.unregisterOnSharedPreferenceChangeListener(listener);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 处理加密过渡</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">handleTransition</span><span class="params">()</span></span>&#123;</span><br><span class="line">        Map&lt;String, ?&gt; oldMap = mSharedPreferences.getAll();</span><br><span class="line">        Map&lt;String, String&gt; newMap = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span> (Map.Entry&lt;String, ?&gt; entry : oldMap.entrySet())&#123;</span><br><span class="line">            Log.i(TAG, <span class="string">"key:"</span>+entry.getKey()+<span class="string">", value:"</span>+ entry.getValue());</span><br><span class="line">            newMap.put(encryptPreference(entry.getKey()), encryptPreference(entry.getValue().toString()));</span><br><span class="line">        &#125;</span><br><span class="line">        Editor editor = mSharedPreferences.edit();</span><br><span class="line">        editor.clear().commit();</span><br><span class="line">        <span class="keyword">for</span> (Map.Entry&lt;String, String&gt; entry : newMap.entrySet())&#123;</span><br><span class="line">            editor.putString(entry.getKey(), entry.getValue());</span><br><span class="line">        &#125;</span><br><span class="line">        editor.commit();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 自动加密Editor</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">SecurityEditor</span> <span class="keyword">implements</span> <span class="title">Editor</span> </span>&#123;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">private</span> Editor mEditor;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * constructor</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="function"><span class="keyword">private</span> <span class="title">SecurityEditor</span><span class="params">()</span></span>&#123;</span><br><span class="line">            mEditor = mSharedPreferences.edit();</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> Editor <span class="title">putString</span><span class="params">(String key, String value)</span> </span>&#123;</span><br><span class="line">            mEditor.putString(encryptPreference(key), encryptPreference(value));</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> Editor <span class="title">putStringSet</span><span class="params">(String key, Set&lt;String&gt; values)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">final</span> Set&lt;String&gt; encryptSet = <span class="keyword">new</span> HashSet&lt;&gt;();</span><br><span class="line">            <span class="keyword">for</span> (String value : values)&#123;</span><br><span class="line">                encryptSet.add(encryptPreference(value));</span><br><span class="line">            &#125;</span><br><span class="line">            mEditor.putStringSet(encryptPreference(key), encryptSet);</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> Editor <span class="title">putInt</span><span class="params">(String key, <span class="keyword">int</span> value)</span> </span>&#123;</span><br><span class="line">            mEditor.putString(encryptPreference(key), encryptPreference(Integer.toString(value)));</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> Editor <span class="title">putLong</span><span class="params">(String key, <span class="keyword">long</span> value)</span> </span>&#123;</span><br><span class="line">            mEditor.putString(encryptPreference(key), encryptPreference(Long.toString(value)));</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> Editor <span class="title">putFloat</span><span class="params">(String key, <span class="keyword">float</span> value)</span> </span>&#123;</span><br><span class="line">            mEditor.putString(encryptPreference(key), encryptPreference(Float.toString(value)));</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> Editor <span class="title">putBoolean</span><span class="params">(String key, <span class="keyword">boolean</span> value)</span> </span>&#123;</span><br><span class="line">            mEditor.putString(encryptPreference(key), encryptPreference(Boolean.toString(value)));</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> Editor <span class="title">remove</span><span class="params">(String key)</span> </span>&#123;</span><br><span class="line">            mEditor.remove(encryptPreference(key));</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * Mark in the editor to remove all values from the preferences.</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span> this</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> Editor <span class="title">clear</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            mEditor.clear();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 提交数据到本地</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span> Boolean 判断是否提交成功</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">commit</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            </span><br><span class="line">            <span class="keyword">return</span> mEditor.commit();</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * Unlike commit(), which writes its preferences out to persistent storage synchronously,</span></span><br><span class="line"><span class="comment">         * apply() commits its changes to the in-memory SharedPreferences immediately but starts</span></span><br><span class="line"><span class="comment">         * an asynchronous commit to disk and you won't be notified of any failures.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="meta">@TargetApi</span>(Build.VERSION_CODES.GINGERBREAD)</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">apply</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">if</span> (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.GINGERBREAD) &#123;</span><br><span class="line">                mEditor.apply();</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                commit();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><font>2. 新建<code>EncryptUtil.java</code>：<br><br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> android.annotation.SuppressLint;</span><br><span class="line"><span class="keyword">import</span> android.content.Context;</span><br><span class="line"><span class="keyword">import</span> android.os.Build;</span><br><span class="line"><span class="keyword">import</span> android.provider.Settings;</span><br><span class="line"><span class="keyword">import</span> android.text.TextUtils;</span><br><span class="line"><span class="keyword">import</span> android.util.Base64;</span><br><span class="line"><span class="keyword">import</span> android.util.Log;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.security.MessageDigest;</span><br><span class="line"><span class="keyword">import</span> java.security.NoSuchAlgorithmException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.crypto.Cipher;</span><br><span class="line"><span class="keyword">import</span> javax.crypto.spec.SecretKeySpec;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * AES加密解密工具</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> Max</span></span><br><span class="line"><span class="comment"> * 2016年11月25日15:25:17</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">EncryptUtil</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">private</span> String key;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> EncryptUtil instance;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String TAG = EncryptUtil.class.getSimpleName();</span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="title">EncryptUtil</span><span class="params">(Context context)</span></span>&#123;</span><br><span class="line">        String serialNo = getDeviceSerialNumber(context);</span><br><span class="line">        <span class="comment">//加密随机字符串生成AES key</span></span><br><span class="line">        key = SHA(serialNo + <span class="string">"#$ERDTS$D%F^Gojikbh"</span>).substring(<span class="number">0</span>, <span class="number">16</span>);</span><br><span class="line">        Log.e(TAG, key);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 单例模式</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> context context</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> EncryptUtil <span class="title">getInstance</span><span class="params">(Context context)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (instance == <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">synchronized</span> (EncryptUtil.class)&#123;</span><br><span class="line">                <span class="keyword">if</span> (instance == <span class="keyword">null</span>)&#123;</span><br><span class="line">                    instance = <span class="keyword">new</span> EncryptUtil(context);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">return</span> instance;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Gets the hardware serial number of this device.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> serial number or Settings.Secure.ANDROID_ID if not available.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@SuppressLint</span>(<span class="string">"HardwareIds"</span>)</span><br><span class="line">    <span class="function"><span class="keyword">private</span> String <span class="title">getDeviceSerialNumber</span><span class="params">(Context context)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// We're using the Reflection API because Build.SERIAL is only available</span></span><br><span class="line">        <span class="comment">// since API Level 9 (Gingerbread, Android 2.3).</span></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            String deviceSerial = (String) Build.class.getField(<span class="string">"SERIAL"</span>).get(<span class="keyword">null</span>);</span><br><span class="line">            <span class="keyword">if</span> (TextUtils.isEmpty(deviceSerial)) &#123;</span><br><span class="line">                <span class="keyword">return</span> Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> deviceSerial;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception ignored) &#123;</span><br><span class="line">            <span class="comment">// Fall back  to Android_ID</span></span><br><span class="line">            <span class="keyword">return</span> Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * SHA加密</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> strText 明文</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> String <span class="title">SHA</span><span class="params">(<span class="keyword">final</span> String strText)</span></span>&#123;</span><br><span class="line">        <span class="comment">// 返回值</span></span><br><span class="line">        String strResult = <span class="keyword">null</span>;</span><br><span class="line">        <span class="comment">// 是否是有效字符串</span></span><br><span class="line">        <span class="keyword">if</span> (strText != <span class="keyword">null</span> &amp;&amp; strText.length() &gt; <span class="number">0</span>)&#123;</span><br><span class="line">            <span class="keyword">try</span>&#123;</span><br><span class="line">                <span class="comment">// SHA 加密开始</span></span><br><span class="line">                MessageDigest messageDigest = MessageDigest.getInstance(<span class="string">"SHA-256"</span>);</span><br><span class="line">                <span class="comment">// 传入要加密的字符串</span></span><br><span class="line">                messageDigest.update(strText.getBytes());</span><br><span class="line">                <span class="keyword">byte</span> byteBuffer[] = messageDigest.digest();</span><br><span class="line">                StringBuffer strHexString = <span class="keyword">new</span> StringBuffer();</span><br><span class="line">                <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; byteBuffer.length; i++)&#123;</span><br><span class="line">                    String hex = Integer.toHexString(<span class="number">0xff</span> &amp; byteBuffer[i]);</span><br><span class="line">                    <span class="keyword">if</span> (hex.length() == <span class="number">1</span>)&#123;</span><br><span class="line">                        strHexString.append(<span class="string">'0'</span>);</span><br><span class="line">                    &#125;</span><br><span class="line">                    strHexString.append(hex);</span><br><span class="line">                &#125;</span><br><span class="line">                strResult = strHexString.toString();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (NoSuchAlgorithmException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">return</span> strResult;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * AES128加密</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> plainText 明文</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">encrypt</span><span class="params">(String plainText)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            Cipher cipher = Cipher.getInstance(<span class="string">"AES/ECB/PKCS5Padding"</span>);</span><br><span class="line">            SecretKeySpec keyspec = <span class="keyword">new</span> SecretKeySpec(key.getBytes(), <span class="string">"AES"</span>);</span><br><span class="line">            cipher.init(Cipher.ENCRYPT_MODE, keyspec);</span><br><span class="line">            <span class="keyword">byte</span>[] encrypted = cipher.doFinal(plainText.getBytes());</span><br><span class="line">            <span class="keyword">return</span> Base64.encodeToString(encrypted, Base64.NO_WRAP);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * AES128解密</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> cipherText 密文</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">decrypt</span><span class="params">(String cipherText)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">byte</span>[] encrypted1 = Base64.decode(cipherText, Base64.NO_WRAP);</span><br><span class="line">            Cipher cipher = Cipher.getInstance(<span class="string">"AES/ECB/PKCS5Padding"</span>);</span><br><span class="line">            SecretKeySpec keyspec = <span class="keyword">new</span> SecretKeySpec(key.getBytes(), <span class="string">"AES"</span>);</span><br><span class="line">            cipher.init(Cipher.DECRYPT_MODE, keyspec);</span><br><span class="line">            <span class="keyword">byte</span>[] original = cipher.doFinal(encrypted1);</span><br><span class="line">            String originalString = <span class="keyword">new</span> String(original);</span><br><span class="line">            <span class="keyword">return</span> originalString;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br>作者采用的加密逻辑为：<br><br>&gt; 我们实现了SharedPreference接口和SharedPreference.Editor接口，重写了保存数据和取出数据的方法，我们在保存数据和取出数据的时候加了加解密层，这样可以保证我们在操作自定义的SharedPreference时候像调用原生的一样简单。<br>&gt; 我采用的是AES128的加密方式，首先获取当前设备的序列号，然后拼接一个随机字符串，生成hash值，作为AES加密的key<br><br>现在还不用研究这些代码，只要记住SecuritySharedPreference的使用方法和普通的SharedPreferences相同就行了。（EncrypUtil本章中暂时用不到）<br>在以后的章节中我们会逐渐学习使用自定义主密码+签名的方式来生成AES256加密级别的key，这将会帮助我们实现密码被盗后通过更改签名来阻止数据被破解。<br><br>下面我们开始把第一章中使用到的SharedPreferences存取全部替换为SecuritySharedPreference：<br><br>## 2.2. LoginActivity重制<br><br><strong><code>LoginActivity.java</code>：</strong><br>（注：如果要全部复制，注意第一行的包名路径要改为你自己的package。后面的文章将不再提醒。）<br><br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.likianta.anykey;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> android.content.Context;</span><br><span class="line"><span class="keyword">import</span> android.content.Intent;</span><br><span class="line"><span class="keyword">import</span> android.content.SharedPreferences;</span><br><span class="line"><span class="keyword">import</span> android.os.Bundle;</span><br><span class="line"><span class="keyword">import</span> android.support.v7.app.AppCompatActivity;</span><br><span class="line"><span class="keyword">import</span> android.text.method.PasswordTransformationMethod;</span><br><span class="line"><span class="keyword">import</span> android.view.KeyEvent;</span><br><span class="line"><span class="keyword">import</span> android.view.View;</span><br><span class="line"><span class="keyword">import</span> android.view.animation.AlphaAnimation;</span><br><span class="line"><span class="keyword">import</span> android.view.inputmethod.InputMethodManager;</span><br><span class="line"><span class="keyword">import</span> android.widget.Button;</span><br><span class="line"><span class="keyword">import</span> android.widget.EditText;</span><br><span class="line"><span class="keyword">import</span> android.widget.TextView;</span><br><span class="line"><span class="keyword">import</span> android.widget.Toast;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Created by Likianta_DoDoRa on 2017/11/9 0009.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LoginActivity</span> <span class="keyword">extends</span> <span class="title">AppCompatActivity</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">final</span> String DEFAULT = <span class="string">"44d5fz533393"</span>;</span><br><span class="line">    <span class="keyword">private</span> EditText etPassword;</span><br><span class="line">    <span class="keyword">private</span> TextView loginWelcome;</span><br><span class="line">    <span class="keyword">private</span> Button loginOn;</span><br><span class="line">    <span class="keyword">private</span> String passwordValue;</span><br><span class="line">    <span class="keyword">private</span> SharedPreferences sharedPreferences;</span><br><span class="line">    <span class="keyword">private</span> SecuritySharedPreference securitySharedPreference;</span><br><span class="line">    <span class="keyword">private</span> EncryptUtil encryptUtil;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>.onCreate(savedInstanceState);</span><br><span class="line">        setContentView(R.layout.activity_login);</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//隐藏标题栏</span></span><br><span class="line">        <span class="keyword">if</span> (getSupportActionBar() != <span class="keyword">null</span>) &#123;</span><br><span class="line">            getSupportActionBar().hide();</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//绑定按钮</span></span><br><span class="line">        etPassword = (EditText) findViewById(R.id.et_password);</span><br><span class="line">        loginWelcome = (TextView) findViewById(R.id.login_welcome);</span><br><span class="line">        loginOn = (Button) findViewById(R.id.login_on);</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//以密文形式显示你的输入</span></span><br><span class="line">        etPassword.setTransformationMethod(PasswordTransformationMethod.getInstance());</span><br><span class="line">        </span><br><span class="line">        <span class="comment">/*</span></span><br><span class="line"><span class="comment">        //这些代码可以删除了</span></span><br><span class="line"><span class="comment">        sharedPreferences = this.getSharedPreferences("UserInfo", Context.MODE_PRIVATE); </span></span><br><span class="line"><span class="comment">        final String saved_userPassword = sharedPreferences.getString("UserPassword", "N/A");</span></span><br><span class="line"><span class="comment">        </span></span><br><span class="line"><span class="comment">        final SharedPreferences.Editor editor = sharedPreferences.edit(); //SharedPreferences是抽象类，不能直接编辑，因此创造一个editor来负责sp的读写操作</span></span><br><span class="line"><span class="comment">        */</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">//SecuritySharedPreference</span></span><br><span class="line">        securitySharedPreference = <span class="keyword">new</span> SecuritySharedPreference(getApplicationContext(), <span class="string">"user_login"</span>, MODE_PRIVATE); <span class="comment">//PRIVATE模式表示只有本应用可以读写该实例</span></span><br><span class="line">        <span class="keyword">final</span> String saved_masterPassword = securitySharedPreference.getString(<span class="string">"MasterPassword"</span>, DEFAULT); <span class="comment">//第一个参数是键，第二个参数是get不到该键时的返回值</span></span><br><span class="line">        <span class="comment">//我们在第一次安装该应用时，sharedPreferences肯定啥都get不到，所以就会返回第二个参数DEFAULT，这是我们判断用户是不是初次使用的重要依据</span></span><br><span class="line">        <span class="keyword">final</span> SecuritySharedPreference.Editor editor = securitySharedPreference.edit();</span><br><span class="line">        LogUtil.d(<span class="string">"Your masterPassword is: "</span> + saved_masterPassword);</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//判断该用哪条欢迎语</span></span><br><span class="line">        changeLoginWelcome(saved_masterPassword);</span><br><span class="line">        <span class="comment">//首次登录判断的业务逻辑为：判断密码是不是DEFAULT，是的话就是首次登录，此时文本框的欢迎词就变了；不是的话就什么事情也不做</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">//触发点击事件，监听登录按钮</span></span><br><span class="line">        loginOn.setOnClickListener(<span class="keyword">new</span> View.OnClickListener() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View view)</span> </span>&#123;</span><br><span class="line">                passwordValue = etPassword.getText().toString().trim(); <span class="comment">//trim()函数可以消除字符串前后的空白符，避免用户手误多按一个空格</span></span><br><span class="line">                <span class="keyword">if</span> (saved_masterPassword.equals(DEFAULT)) &#123;</span><br><span class="line">                    <span class="comment">//首次使用的业务逻辑</span></span><br><span class="line">                    editor.putString(<span class="string">"MasterPassword"</span>, passwordValue).apply();</span><br><span class="line">                    </span><br><span class="line">                    Toast.makeText(LoginActivity.<span class="keyword">this</span>, <span class="string">"创建成功"</span>, Toast.LENGTH_SHORT).show();</span><br><span class="line">                    </span><br><span class="line">                    <span class="comment">//跳转至主界面</span></span><br><span class="line">                    Intent intent = <span class="keyword">new</span> Intent(LoginActivity.<span class="keyword">this</span>, MainActivity.class);</span><br><span class="line">                    LoginActivity.<span class="keyword">this</span>.startActivity(intent);</span><br><span class="line">                    finish();</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="comment">//非首次登录时的常规业务</span></span><br><span class="line">                    <span class="keyword">if</span> (passwordValue.equals(saved_masterPassword)) &#123;</span><br><span class="line">                        </span><br><span class="line">                        Toast.makeText(LoginActivity.<span class="keyword">this</span>, <span class="string">"登录成功"</span>, Toast.LENGTH_SHORT).show();</span><br><span class="line">                        </span><br><span class="line">                        <span class="comment">//跳转至主界面</span></span><br><span class="line">                        Intent intent = <span class="keyword">new</span> Intent(LoginActivity.<span class="keyword">this</span>, MainActivity.class);</span><br><span class="line">                        LoginActivity.<span class="keyword">this</span>.startActivity(intent);</span><br><span class="line">                        finish();</span><br><span class="line">                    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                        <span class="comment">//密码错误时的业务</span></span><br><span class="line">                        changeLoginWelcome(<span class="string">"WRONG_CODE"</span>);</span><br><span class="line">                        etPassword.setText(<span class="string">""</span>); <span class="comment">//重置密码框为空</span></span><br><span class="line">                        </span><br><span class="line">                        <span class="comment">//让输入框重新获取焦点</span></span><br><span class="line">                        etPassword.setFocusable(<span class="keyword">true</span>);</span><br><span class="line">                        etPassword.setFocusableInTouchMode(<span class="keyword">true</span>);</span><br><span class="line">                        etPassword.requestFocus();</span><br><span class="line">                        </span><br><span class="line">                        <span class="comment">//通过调用输入管理器来弹出软键盘</span></span><br><span class="line">                        InputMethodManager inputMethodManager = (InputMethodManager) etPassword.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);</span><br><span class="line">                        inputMethodManager.showSoftInput(etPassword, <span class="number">0</span>);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        </span><br><span class="line">        etPassword.setOnKeyListener(<span class="keyword">new</span> View.OnKeyListener() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">onKey</span><span class="params">(View view, <span class="keyword">int</span> i, KeyEvent keyEvent)</span> </span>&#123;</span><br><span class="line">                <span class="keyword">if</span> (i == keyEvent.KEYCODE_ENTER) &#123;</span><br><span class="line">                    loginOn.callOnClick(); <span class="comment">//callOnClick是performClick的简化版，适合简单触发点击监听事件</span></span><br><span class="line">                    <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">                <span class="comment">/*</span></span><br><span class="line"><span class="comment">                 * 另外再设置一个监听软键盘输入，当输入Enter的时候，也能触发上面的登录按钮</span></span><br><span class="line"><span class="comment">                 * 关于返回值的说明</span></span><br><span class="line"><span class="comment">                 * 返回值为true，表示事件已完全处理，系统无需再处理此键</span></span><br><span class="line"><span class="comment">                 * 返回值为false，表示事件处理过后，还要交给系统继续处理</span></span><br><span class="line"><span class="comment">                 * 参考此回答：https://zhidao.baidu.com/question/1430105248859125459.html</span></span><br><span class="line"><span class="comment">                 */</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// Select welcome words.</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">changeLoginWelcome</span><span class="params">(String userCode)</span> </span>&#123;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">switch</span> (userCode) &#123;</span><br><span class="line">            <span class="keyword">case</span> DEFAULT:</span><br><span class="line">                <span class="comment">// 首次使用时的欢迎语</span></span><br><span class="line">                loginWelcome.setText(<span class="string">"首次使用\n请创建你的主密码"</span>);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">"WRONG_CODE"</span>:</span><br><span class="line">                <span class="comment">// 密码输入错误时的欢迎语</span></span><br><span class="line">                loginWelcome.setText(<span class="string">"密码错误\n请重新登录"</span>); <span class="comment">// 在“欢迎词”中显示出错提示</span></span><br><span class="line">                loginWelcome.setTextColor(<span class="number">0xFFF4297E</span>);</span><br><span class="line">                <span class="keyword">final</span> AlphaAnimation alphaAnimation = <span class="keyword">new</span> AlphaAnimation(<span class="number">1.0f</span>, <span class="number">0.6f</span>); <span class="comment">// 不透明度的参数取值是小数，范围在0-1之间，0表示完全透明，1表示完全显示</span></span><br><span class="line">                alphaAnimation.setDuration(<span class="number">500</span>); <span class="comment">// 动画持续时间</span></span><br><span class="line">                alphaAnimation.setFillAfter(<span class="keyword">true</span>); <span class="comment">// 表示动画停留在最终完成的状态上</span></span><br><span class="line">                loginWelcome.setAnimation(alphaAnimation);</span><br><span class="line">                alphaAnimation.startNow();</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//监听按下的按键，如果按下了返回键，则退出登录界面</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">onKeyDown</span><span class="params">(<span class="keyword">int</span> keyCode, KeyEvent keyEvent)</span> </span>&#123;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> (keyCode == KeyEvent.KEYCODE_BACK) &#123;</span><br><span class="line">            LoginActivity.<span class="keyword">this</span>.finish();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">super</span>.onKeyDown(keyCode, keyEvent);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br>至此登录流程已完整实现。下面开始本章的重头戏——表单数据的绑定和加载。<br><br># 3. 填表数据的绑定和加载<br><br>注：这里给一些文件改名了，比如“page_item_all”和“page_item_new”改成了“page_card_list”和“page_card_new”（使用shift+f6可以全局改名）。<br>另外删掉了一些没有用到的类，具体变更可参照下图：<br><br><img src="http://ozurciydg.bkt.clouddn.com/17-12-3/80000455.jpg" alt=""><br><br>## 3.1. 右分页布局<br><br>在04章中已经制作好了右分页的布局，这里重新贴出整体的代码：<br><br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span><br><span class="line"><span class="tag">&lt;<span class="name">RelativeLayout</span> <span class="attr">xmlns:android</span>=<span class="string">"http://schemas.android.com/apk/res/android"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:app</span>=<span class="string">"http://schemas.android.com/apk/res-auto"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:tools</span>=<span class="string">"http://schemas.android.com/tools"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_width</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_height</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:background</span>=<span class="string">"@color/mycolorBackground"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:padding</span>=<span class="string">"5dp"</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 最外层是一个RelativeLayout，内边距5dp，背景色与左分页背景同色 --&gt;</span></span><br><span class="line">    </span><br><span class="line">    <span class="tag">&lt;<span class="name">ScrollView</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_width</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_height</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_above</span>=<span class="string">"@id/userInfoSave"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_marginBottom</span>=<span class="string">"5dp"</span>&gt;</span></span><br><span class="line">        </span><br><span class="line">        <span class="tag">&lt;<span class="name">RelativeLayout</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_width</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_height</span>=<span class="string">"wrap_content"</span>&gt;</span></span><br><span class="line">            <span class="comment">&lt;!-- 这里同样使用的是RelativeLayout。</span></span><br><span class="line"><span class="comment">             因为考虑到以后可能还需要在上面贴一些控件等……所以用相对布局更好一些--&gt;</span></span><br><span class="line">            </span><br><span class="line">            <span class="comment">&lt;!-- 头像的背景，根据头像主色调来生成（方法在函数中实现） --&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">ImageView</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:id</span>=<span class="string">"@+id/userHeadBackground"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_width</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_height</span>=<span class="string">"108dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:background</span>=<span class="string">"#8e8e8e"</span> /&gt;</span></span><br><span class="line">            </span><br><span class="line">            <span class="comment">&lt;!-- 使用开源控件CircleImageView制作圆形头像 --&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">de.hdodenhof.circleimageview.CircleImageView</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:id</span>=<span class="string">"@+id/userHead"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_width</span>=<span class="string">"96dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_height</span>=<span class="string">"96dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_centerHorizontal</span>=<span class="string">"true"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_marginTop</span>=<span class="string">"60dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:padding</span>=<span class="string">"5dp"</span> /&gt;</span></span><br><span class="line">            </span><br><span class="line">            <span class="comment">&lt;!-- 常规表单填写 --&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">TableLayout</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:id</span>=<span class="string">"@+id/table1"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_width</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_height</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_below</span>=<span class="string">"@id/userHead"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:padding</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:shrinkColumns</span>=<span class="string">"1"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:stretchColumns</span>=<span class="string">"1"</span>&gt;</span></span><br><span class="line">                </span><br><span class="line">                <span class="comment">&lt;!-- 第一行，标题栏 --&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">TableRow</span>&gt;</span></span><br><span class="line">                    </span><br><span class="line">                    <span class="tag">&lt;<span class="name">TextView</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_margin</span>=<span class="string">"5dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:text</span>=<span class="string">"标题"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:textSize</span>=<span class="string">"16sp"</span> /&gt;</span></span><br><span class="line">                    </span><br><span class="line">                    <span class="tag">&lt;<span class="name">EditText</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:id</span>=<span class="string">"@+id/userTitle"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_height</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_margin</span>=<span class="string">"5dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_span</span>=<span class="string">"5"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:background</span>=<span class="string">"@drawable/bg_edittext"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:paddingLeft</span>=<span class="string">"16dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:paddingRight</span>=<span class="string">"16dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:singleLine</span>=<span class="string">"true"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:textColorHint</span>=<span class="string">"@color/colorAccent"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:textSize</span>=<span class="string">"16sp"</span> /&gt;</span></span><br><span class="line">                    </span><br><span class="line">                    <span class="comment">&lt;!-- 分组按钮 --&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">ImageView</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:id</span>=<span class="string">"@+id/userTitleGroup"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_width</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_height</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_gravity</span>=<span class="string">"center"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_margin</span>=<span class="string">"5dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:padding</span>=<span class="string">"2dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:src</span>=<span class="string">"@drawable/icon_folder"</span> /&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">TableRow</span>&gt;</span></span><br><span class="line">                </span><br><span class="line">                <span class="comment">&lt;!-- 第二行，帐号栏 --&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">TableRow</span>&gt;</span></span><br><span class="line">                    </span><br><span class="line">                    <span class="tag">&lt;<span class="name">TextView</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_margin</span>=<span class="string">"5dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:text</span>=<span class="string">"帐号"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:textSize</span>=<span class="string">"16sp"</span> /&gt;</span></span><br><span class="line">                    </span><br><span class="line">                    <span class="tag">&lt;<span class="name">EditText</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:id</span>=<span class="string">"@+id/userName"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_height</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_margin</span>=<span class="string">"5dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_span</span>=<span class="string">"5"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:background</span>=<span class="string">"@drawable/bg_edittext"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:paddingLeft</span>=<span class="string">"16dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:paddingRight</span>=<span class="string">"16dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:singleLine</span>=<span class="string">"true"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:textSize</span>=<span class="string">"16sp"</span> /&gt;</span></span><br><span class="line">                    </span><br><span class="line">                    <span class="comment">&lt;!-- 这个按钮是用来关联同标题的小号的，点击后会让你设置哪个是大号，哪个是隐私号，哪些是小号……</span></span><br><span class="line"><span class="comment">                     小号还可以手动排序 --&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">ImageView</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:id</span>=<span class="string">"@+id/userNameLink"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_width</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_height</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_gravity</span>=<span class="string">"center"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_margin</span>=<span class="string">"5dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:padding</span>=<span class="string">"2dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:src</span>=<span class="string">"@drawable/icon_attach"</span> /&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">TableRow</span>&gt;</span></span><br><span class="line">                </span><br><span class="line">                <span class="comment">&lt;!-- 第三行，密码栏 --&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">TableRow</span>&gt;</span></span><br><span class="line">                    </span><br><span class="line">                    <span class="tag">&lt;<span class="name">TextView</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_margin</span>=<span class="string">"5dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:text</span>=<span class="string">"密码"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:textSize</span>=<span class="string">"16sp"</span> /&gt;</span></span><br><span class="line">                    </span><br><span class="line">                    <span class="tag">&lt;<span class="name">EditText</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:id</span>=<span class="string">"@+id/userPassword"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_height</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_margin</span>=<span class="string">"5dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_span</span>=<span class="string">"5"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:background</span>=<span class="string">"@drawable/bg_edittext"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:paddingLeft</span>=<span class="string">"16dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:paddingRight</span>=<span class="string">"16dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:singleLine</span>=<span class="string">"true"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:textSize</span>=<span class="string">"16sp"</span> /&gt;</span></span><br><span class="line">                    </span><br><span class="line">                    <span class="comment">&lt;!-- 随机密码生成按钮 --&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">ImageView</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:id</span>=<span class="string">"@+id/userPasswordRandom"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_width</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_height</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_gravity</span>=<span class="string">"center"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_margin</span>=<span class="string">"5dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:padding</span>=<span class="string">"4dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:src</span>=<span class="string">"@drawable/icon_random"</span> /&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">TableRow</span>&gt;</span></span><br><span class="line">                </span><br><span class="line">                <span class="comment">&lt;!-- 第四行，比较特殊，是一排绑定按钮 --&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">TableRow</span>&gt;</span></span><br><span class="line"></span><br><span class="line">                    <span class="tag">&lt;<span class="name">TextView</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_gravity</span>=<span class="string">"center_vertical"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_margin</span>=<span class="string">"5dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:text</span>=<span class="string">"绑定"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:textSize</span>=<span class="string">"20sp"</span> /&gt;</span></span><br><span class="line"></span><br><span class="line">                    <span class="comment">&lt;!-- 这些绑定按钮可自定义还可横向滚动 --&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">HorizontalScrollView</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:id</span>=<span class="string">"@+id/userBoundBar"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_gravity</span>=<span class="string">"center"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_span</span>=<span class="string">"5"</span>&gt;</span></span><br><span class="line"></span><br><span class="line">                        <span class="tag">&lt;<span class="name">LinearLayout</span></span></span><br><span class="line"><span class="tag">                            <span class="attr">android:layout_width</span>=<span class="string">"wrap_content"</span></span></span><br><span class="line"><span class="tag">                            <span class="attr">android:layout_height</span>=<span class="string">"match_parent"</span>&gt;</span></span><br><span class="line"></span><br><span class="line">                            <span class="tag">&lt;<span class="name">ImageView</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:id</span>=<span class="string">"@+id/userBoundQq"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_width</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_height</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_gravity</span>=<span class="string">"center"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_margin</span>=<span class="string">"15dp"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:src</span>=<span class="string">"@drawable/icon_bound_qq"</span> /&gt;</span></span><br><span class="line"></span><br><span class="line">                            <span class="tag">&lt;<span class="name">ImageView</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:id</span>=<span class="string">"@+id/userBoundWeixin"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_width</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_height</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_gravity</span>=<span class="string">"center"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_margin</span>=<span class="string">"15dp"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:src</span>=<span class="string">"@drawable/icon_bound_weixin"</span> /&gt;</span></span><br><span class="line"></span><br><span class="line">                            <span class="tag">&lt;<span class="name">ImageView</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:id</span>=<span class="string">"@+id/userBoundWeibo"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_width</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_height</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_gravity</span>=<span class="string">"center"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_margin</span>=<span class="string">"15dp"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:src</span>=<span class="string">"@drawable/icon_bound_weibo"</span> /&gt;</span></span><br><span class="line"></span><br><span class="line">                            <span class="tag">&lt;<span class="name">ImageView</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:id</span>=<span class="string">"@+id/userBoundPhone"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_width</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_height</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_gravity</span>=<span class="string">"center"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_margin</span>=<span class="string">"15dp"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:src</span>=<span class="string">"@drawable/icon_bound_phone"</span> /&gt;</span></span><br><span class="line"></span><br><span class="line">                            <span class="tag">&lt;<span class="name">ImageView</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:id</span>=<span class="string">"@+id/userBoundEmail"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_width</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_height</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_gravity</span>=<span class="string">"center"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_margin</span>=<span class="string">"15dp"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:src</span>=<span class="string">"@drawable/icon_bound_email"</span> /&gt;</span></span><br><span class="line"></span><br><span class="line">                            <span class="tag">&lt;<span class="name">ImageView</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:id</span>=<span class="string">"@+id/userBoundWangyi"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_width</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_height</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_gravity</span>=<span class="string">"center"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:layout_margin</span>=<span class="string">"15dp"</span></span></span><br><span class="line"><span class="tag">                                <span class="attr">android:src</span>=<span class="string">"@drawable/icon_bound_wangyi"</span> /&gt;</span></span><br><span class="line">                        <span class="tag">&lt;/<span class="name">LinearLayout</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;/<span class="name">HorizontalScrollView</span>&gt;</span></span><br><span class="line"></span><br><span class="line">                    <span class="comment">&lt;!-- 对绑定按钮进行详细设置，比如默认值、同类型小号（红色显示）、新增自定义字段等 --&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">ImageView</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:id</span>=<span class="string">"@+id/userBoundMore"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_width</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_height</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_gravity</span>=<span class="string">"center"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_margin</span>=<span class="string">"5dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:src</span>=<span class="string">"@drawable/icon_more"</span> /&gt;</span></span><br><span class="line"></span><br><span class="line">                <span class="tag">&lt;/<span class="name">TableRow</span>&gt;</span></span><br><span class="line"></span><br><span class="line">                </span><br><span class="line">                <span class="comment">&lt;!-- 第五行，URL --&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">TableRow</span>&gt;</span></span><br><span class="line">                    </span><br><span class="line">                    <span class="tag">&lt;<span class="name">TextView</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_margin</span>=<span class="string">"5dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:text</span>=<span class="string">"URL"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:textSize</span>=<span class="string">"16sp"</span> /&gt;</span></span><br><span class="line">                    </span><br><span class="line">                    <span class="comment">&lt;!-- 默认是单行输入的 --&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">EditText</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:id</span>=<span class="string">"@+id/userUrl"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_height</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_margin</span>=<span class="string">"5dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_span</span>=<span class="string">"5"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:background</span>=<span class="string">"@drawable/bg_edittext"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:paddingLeft</span>=<span class="string">"16dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:paddingRight</span>=<span class="string">"16dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:singleLine</span>=<span class="string">"true"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:textSize</span>=<span class="string">"16sp"</span> /&gt;</span></span><br><span class="line">                    </span><br><span class="line">                    <span class="comment">&lt;!-- 通过此按钮可以切换单/多行输入模式 --&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">ImageView</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:id</span>=<span class="string">"@+id/userUrlMultilines"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_width</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_height</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_gravity</span>=<span class="string">"center"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_margin</span>=<span class="string">"5dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:src</span>=<span class="string">"@drawable/icon_add2"</span> /&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">TableRow</span>&gt;</span></span><br><span class="line">                </span><br><span class="line">                <span class="comment">&lt;!-- 第六行，备注栏 --&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">TableRow</span>&gt;</span></span><br><span class="line">                    </span><br><span class="line">                    <span class="comment">&lt;!-- 备注栏是多行输入的 --&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">EditText</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:id</span>=<span class="string">"@+id/userNote"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_marginTop</span>=<span class="string">"15dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:layout_span</span>=<span class="string">"7"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:background</span>=<span class="string">"@drawable/bg_edittext"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:hint</span>=<span class="string">"请在此输入备注"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:padding</span>=<span class="string">"16dp"</span></span></span><br><span class="line"><span class="tag">                        <span class="attr">android:textSize</span>=<span class="string">"14sp"</span> /&gt;</span></span><br><span class="line">                </span><br><span class="line">                <span class="tag">&lt;/<span class="name">TableRow</span>&gt;</span></span><br><span class="line">            </span><br><span class="line">            <span class="tag">&lt;/<span class="name">TableLayout</span>&gt;</span></span><br><span class="line">            </span><br><span class="line">            </span><br><span class="line">            <span class="comment">&lt;!-- 这个小按钮比较特殊，是专为备注栏服务的，功能是点击一下生成一条分割线</span></span><br><span class="line"><span class="comment">             默认状态是隐藏的，只有当备注栏获取焦点时才会出现 --&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">ImageView</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:id</span>=<span class="string">"@+id/userNoteSlash"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_width</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_height</span>=<span class="string">"30dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_alignBottom</span>=<span class="string">"@id/table1"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_alignParentEnd</span>=<span class="string">"true"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_marginBottom</span>=<span class="string">"40dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_marginEnd</span>=<span class="string">"10dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:background</span>=<span class="string">"#0000"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:padding</span>=<span class="string">"6dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:src</span>=<span class="string">"@drawable/icon_slash"</span> /&gt;</span></span><br><span class="line">        </span><br><span class="line">        <span class="tag">&lt;/<span class="name">RelativeLayout</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">ScrollView</span>&gt;</span></span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    <span class="comment">&lt;!-- 保存按钮 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">Button</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:id</span>=<span class="string">"@+id/userInfoSave"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_width</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_height</span>=<span class="string">"wrap_content"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_alignParentBottom</span>=<span class="string">"true"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:background</span>=<span class="string">"@drawable/bg_button"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:text</span>=<span class="string">"保存"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:textSize</span>=<span class="string">"16sp"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:visibility</span>=<span class="string">"visible"</span> /&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">RelativeLayout</span>&gt;</span></span><br></pre></td></tr></table></figure><br><br>布局中用到的drawable资源可以在此下载：链接: <a href="https://pan.baidu.com/s/1geFpBY7" target="_blank" rel="noopener">https://pan.baidu.com/s/1geFpBY7</a> 密码: ivce<br><br>## <strong><font color="red">3.2. 保存用户数据</font></strong><br><br>这里分为三部分来考虑：<br><br>1. 点击保存按钮，产生新的卡片数据<br>2. 在cardList中添加此卡片并出现在左分页中<br>3. 在SecuritySharedPreference中保存卡片数据（保存到<code>/data/data//my_prefs/包名/card_data.xml</code>文件中）<br><br>那么首先我们来看点击保存按钮时的业务：<br><br>### 3.2.1. 点击“保存”按钮时的业务<br><br><font>1. <code>MainActivity.java</code><br><br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MainActivity</span> <span class="keyword">extends</span> <span class="title">AppCompatActivity</span> <span class="keyword">implements</span> <span class="title">View</span>.<span class="title">OnClickListener</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//以下变量是与分页相关的变量</span></span><br><span class="line">    <span class="keyword">private</span> TextView titleAll; <span class="comment">//标题文字“全部”</span></span><br><span class="line">    <span class="keyword">private</span> TextView titleNew; <span class="comment">//标题文字“新增”</span></span><br><span class="line">    <span class="keyword">private</span> CircleIndicator indicator; <span class="comment">//滚动指示器</span></span><br><span class="line">    <span class="keyword">private</span> View page1; <span class="comment">//左分页</span></span><br><span class="line">    <span class="keyword">private</span> View page2; <span class="comment">//右分页</span></span><br><span class="line">    <span class="keyword">private</span> ViewPager viewPager; <span class="comment">//控制分页逻辑的容器</span></span><br><span class="line">    <span class="keyword">private</span> ArrayList&lt;View&gt; pageList; <span class="comment">//装载分页元素的容器</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">//以下变量是与左分页相关的控件</span></span><br><span class="line">    <span class="keyword">private</span> RecyclerView recyclerView1; <span class="comment">//卡片列表，注意改名啦（原先名字是“recyclerView”）</span></span><br><span class="line">    <span class="keyword">public</span> CardAdapter cardAdapter;</span><br><span class="line">    <span class="keyword">public</span> List&lt;Card&gt; cardList = <span class="keyword">new</span> ArrayList&lt;Card&gt;(); <span class="comment">//卡片数据</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">//以下变量是与右分页相关的控件</span></span><br><span class="line">    <span class="keyword">private</span> Button saveUserButton; <span class="comment">//右分页“保存”按钮</span></span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        ...</span><br><span class="line"></span><br><span class="line">        <span class="comment">//用LayoutInflater来绑定布局</span></span><br><span class="line">        LayoutInflater inflater = getLayoutInflater();</span><br><span class="line">        page1 = inflater.inflate(R.layout.page_card_list, <span class="keyword">null</span>); <span class="comment">//预加载左分页</span></span><br><span class="line">        page2 = inflater.inflate(R.layout.page_card_new, <span class="keyword">null</span>); <span class="comment">//预加载右分页</span></span><br><span class="line">        pageList = <span class="keyword">new</span> ArrayList&lt;View&gt;(); <span class="comment">//pageList被实例化为装载View元素的数组</span></span><br><span class="line">        pageList.add(page1);</span><br><span class="line">        pageList.add(page2);</span><br><span class="line">        <span class="comment">//add的先后顺序不要搞错，先add的就是array[0]位置的元素了</span></span><br><span class="line"></span><br><span class="line">        ...</span><br><span class="line"></span><br><span class="line">        <span class="comment">//绑定右分页的按钮</span></span><br><span class="line">        saveUserButton = (Button) page2.findViewById(R.id.userInfoSave);</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//监听按钮点击</span></span><br><span class="line">        ...</span><br><span class="line">        saveUserButton.setOnClickListener(<span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View view)</span> </span>&#123;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">switch</span> (view.getId()) &#123;</span><br><span class="line">            ...</span><br><span class="line">            <span class="keyword">case</span> R.id.userInfoSave:</span><br><span class="line"></span><br><span class="line">                <span class="comment">//点击右分页的保存按钮</span></span><br><span class="line">                LogUtil.d(<span class="string">"You clicked userInfoSave button."</span>);</span><br><span class="line">                </span><br><span class="line">                <span class="comment">//首先判断标题是不是空的，空的话必须填写标题</span></span><br><span class="line">                <span class="keyword">if</span> (<span class="keyword">new</span> SaveUserInfo(page2).isTitleEmpty()) &#123;</span><br><span class="line">                    <span class="comment">//SaveUserInfo.java是重点，会新建一个类来写</span></span><br><span class="line">                    Toast.makeText(MainActivity.<span class="keyword">this</span>, <span class="string">"标题不能为空！"</span>, Toast.LENGTH_SHORT).show();</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                Card card = <span class="keyword">new</span> SaveUserInfo(page2).getNewCard();</span><br><span class="line">                cardList.add(<span class="number">0</span>, card); <span class="comment">//在零号位（也就是第一位）添加这张新卡片</span></span><br><span class="line">                cardAdapter.notifyItemInserted(<span class="number">0</span>); <span class="comment">//添加后要给RecyclerView释放一个更新信号。具体方法写在CardAdapter.java里</span></span><br><span class="line">                viewPager.setCurrentItem(<span class="number">0</span>); <span class="comment">//自动跳转到左分页</span></span><br><span class="line">                recyclerView1.scrollToPosition(<span class="number">0</span>); <span class="comment">//自动跳转到列表首部，方便用户看到自己新增的卡片</span></span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br><font><strong>2. 新建<code>SaveUserInfo.java</code>：</strong><br>（注：如果要全部复制，注意第一行的包名路径要改为你自己的package。后面的文章将不再提醒。）<br><br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.likianta.anykey;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> android.content.Context;</span><br><span class="line"><span class="keyword">import</span> android.content.SharedPreferences;</span><br><span class="line"><span class="keyword">import</span> android.view.View;</span><br><span class="line"><span class="keyword">import</span> android.view.inputmethod.InputMethodManager;</span><br><span class="line"><span class="keyword">import</span> android.widget.EditText;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.google.gson.Gson;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> de.hdodenhof.circleimageview.CircleImageView;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Created by Likianta_DoDoRa on 2017/11/27 0027.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SaveUserInfo</span> <span class="keyword">extends</span> <span class="title">MainActivity</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">private</span> EditText userTitle;</span><br><span class="line">    <span class="keyword">private</span> EditText userName;</span><br><span class="line">    <span class="keyword">private</span> EditText userPassword;</span><br><span class="line">    <span class="keyword">private</span> EditText userUrl;</span><br><span class="line">    <span class="keyword">private</span> EditText userNote;</span><br><span class="line">    <span class="keyword">private</span> CircleImageView userHead;</span><br><span class="line">    <span class="keyword">private</span> String uTitle;</span><br><span class="line">    <span class="keyword">private</span> String uName;</span><br><span class="line">    <span class="keyword">private</span> String uPassword;</span><br><span class="line">    <span class="keyword">private</span> String uUrl;</span><br><span class="line">    <span class="keyword">private</span> String uNote;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">private</span> Card card;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">SaveUserInfo</span><span class="params">(View pageview)</span> </span>&#123;</span><br><span class="line">        </span><br><span class="line">        LogUtil.d(<span class="string">"向SaveUserInfo（）传入右分页布局"</span>);</span><br><span class="line">        </span><br><span class="line">        userTitle = (EditText) pageview.findViewById(R.id.userTitle);</span><br><span class="line">        userName = (EditText) pageview.findViewById(R.id.userName);</span><br><span class="line">        userPassword = (EditText) pageview.findViewById(R.id.userPassword);</span><br><span class="line">        userUrl = (EditText) pageview.findViewById(R.id.userUrl);</span><br><span class="line">        userNote = (EditText) pageview.findViewById(R.id.userNote);</span><br><span class="line">        userHead = (CircleImageView) pageview.findViewById(R.id.userHead);</span><br><span class="line">    </span><br><span class="line">        uTitle = userTitle.getText().toString();</span><br><span class="line">        uName = userName.getText().toString();</span><br><span class="line">        uPassword = userPassword.getText().toString();</span><br><span class="line">        uUrl = userUrl.getText().toString();</span><br><span class="line">        uNote = userNote.getText().toString();</span><br><span class="line">        LogUtil.d(<span class="string">"User note is "</span> + uNote);</span><br><span class="line">        </span><br><span class="line">        getNewCard(); <span class="comment">//生成新卡片的操作</span></span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//检测保存时的标题栏的文字是否为空，空的话禁止保存并提醒填写</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isTitleEmpty</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (uTitle.equals(<span class="string">""</span>)) &#123;</span><br><span class="line">            userTitle.setHint(<span class="string">"请输入标题"</span>);</span><br><span class="line">            userTitle.setFocusable(<span class="keyword">true</span>);</span><br><span class="line">            userTitle.setFocusableInTouchMode(<span class="keyword">true</span>);</span><br><span class="line">            userTitle.requestFocus();</span><br><span class="line">            </span><br><span class="line">            <span class="comment">//通过调用输入管理器来弹出软键盘</span></span><br><span class="line">            InputMethodManager inputMethodManager = (InputMethodManager) userTitle.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);</span><br><span class="line">            inputMethodManager.showSoftInput(userTitle, <span class="number">0</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> Card <span class="title">getNewCard</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        String uSummary = uName + <span class="string">"\n"</span> + uPassword + <span class="string">"\n"</span> + uNote; <span class="comment">//卡片的摘要=用户名+密码+备注</span></span><br><span class="line">        card = <span class="keyword">new</span> Card(uTitle, uSummary); <span class="comment">//目前我们用到的卡片属性只有这两个，后面会逐渐补充完整</span></span><br><span class="line">        <span class="keyword">return</span> card;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br>还记得刚才在MainActivity中点击“保存”按钮时的业务代码吗？<br><br><img src="http://ozurciydg.bkt.clouddn.com/17-12-3/20508938.jpg" alt=""><br><br>然后CardAdapter中还需要添加相关的代码才行：<br><br><font>3. <code>CardAdapter.java</code><br><br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CardAdapter</span> <span class="keyword">extends</span> <span class="title">RecyclerView</span>.<span class="title">Adapter</span>&lt;<span class="title">CardAdapter</span>.<span class="title">ViewHolder</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">add</span><span class="params">(<span class="keyword">int</span> position, Card card)</span> </span>&#123;</span><br><span class="line">        cardList.add(position, card);</span><br><span class="line">        notifyItemInserted(position);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br>当然对于一个CardAdapter来说，光有添加卡片的业务是不行的，还要有删除卡片的业务：<br><br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> android.widget.Toast;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CardAdapter</span> <span class="keyword">extends</span> <span class="title">RecyclerView</span>.<span class="title">Adapter</span>&lt;<span class="title">CardAdapter</span>.<span class="title">ViewHolder</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">add</span><span class="params">(<span class="keyword">int</span> position, Card card)</span> </span>&#123;</span><br><span class="line">        ...</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">remove</span><span class="params">(Context context, <span class="keyword">int</span> position)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (position &lt; <span class="number">0</span>) &#123;</span><br><span class="line">            Toast.makeText(context, <span class="string">"列表中并没有结果!"</span>, Toast.LENGTH_SHORT).show();</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            cardList.remove(position);</span><br><span class="line">            notifyItemRemoved(position);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><br>其实还有更多的操作（比如删除全部卡片）没写，不过那些目前都用不上，等到以后有需求再添加。<br><br><strong>至此，我们已经完成了最初构想的两大部分了：</strong><br><br><strong>1. 点击保存按钮，产生新的卡片数据</strong><br><strong>2. 在cardList中添加此卡片并出现在左分页中</strong><br><br>接下来要做的是完成最后一部分——在SecuritySharedPreference中保存卡片数据。<br><br>### 3.2.2. 保存卡片数据到本地（SavedToMySharedPrefs）<br><br><strong>新建<code>SavedToMySharedPrefs.java</code>：</strong><br><font size="2" color="gray">（注：如果要全部复制，注意第一行的包名路径要改为你自己的package。后面的文章将不再提醒。）</font>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.likianta.anykey;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> android.content.Context;</span><br><span class="line"><span class="keyword">import</span> android.content.SharedPreferences;</span><br><span class="line"><span class="keyword">import</span> android.widget.Toast;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.google.gson.Gson;</span><br><span class="line"><span class="keyword">import</span> com.google.gson.reflect.TypeToken;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.ArrayList;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> android.content.Context.MODE_PRIVATE;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Created by Likianta_DoDoRa on 2017/12/2 0002.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SavedToMySharedPrefs</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//建议在退出程序时调用，以将数据保存到文件中</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">private</span> SecuritySharedPreference securitySharedPreference;</span><br><span class="line">    <span class="keyword">private</span> SharedPreferences.Editor editor;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">SavedToMySharedPrefs</span><span class="params">(Context context, String preferenceName)</span> </span>&#123;</span><br><span class="line">        securitySharedPreference = <span class="keyword">new</span> SecuritySharedPreference(context, preferenceName, MODE_PRIVATE);</span><br><span class="line">        editor = securitySharedPreference.edit();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取cardList</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> List&lt;Card&gt; <span class="title">getCardData</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        </span><br><span class="line">        List&lt;Card&gt; cardList = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">        </span><br><span class="line">        String strJson = securitySharedPreference.getString(<span class="string">"Card"</span>, <span class="keyword">null</span>);</span><br><span class="line">        LogUtil.d(<span class="string">"从已保存的card_data文件中获取列表！strJson="</span>+strJson);</span><br><span class="line">        </span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">null</span> == strJson) &#123;</span><br><span class="line">            LogUtil.d(<span class="string">"获取到的json为空！"</span>);</span><br><span class="line">            <span class="keyword">return</span> cardList;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        Gson gson = <span class="keyword">new</span> Gson();</span><br><span class="line">        cardList = gson.fromJson(strJson, <span class="keyword">new</span> TypeToken&lt;List&lt;Card&gt;&gt;() &#123;</span><br><span class="line">        &#125;.getType());</span><br><span class="line">        <span class="keyword">for</span> (Card card:cardList)&#123;</span><br><span class="line">            LogUtil.d(<span class="string">"Card info 1 "</span>+card.getCardTitle());</span><br><span class="line">            LogUtil.d(<span class="string">"Card info 2 "</span>+card.getCardSummary());</span><br><span class="line">        &#125;</span><br><span class="line">        LogUtil.d(<span class="string">"获取到的cardList是"</span>+cardList);</span><br><span class="line">        <span class="keyword">return</span> cardList;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 保存cardList</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setCardData</span><span class="params">(List&lt;Card&gt; cardList)</span> </span>&#123;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">null</span> == cardList || cardList.size() &lt;= <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        Gson gson = <span class="keyword">new</span> Gson();</span><br><span class="line">        <span class="comment">//转换成json数据，再保存</span></span><br><span class="line">        String strJson = gson.toJson(cardList);</span><br><span class="line">        editor.clear();</span><br><span class="line">        editor.putString(<span class="string">"Card"</span>, strJson);</span><br><span class="line">        editor.apply();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取userItemList</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 保存userItemList</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">     </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>注意代码中我写了两个获取和两个保存方法（后面两个还没有写相关代码）。<br>这里将Card和UserItem分开考虑，它们的关系为：</p>
<table><br><br>    <tr><br>        <td><br>        </td><td>card_data.xml（加密保存）</td><br>        <td>user_data.xml（加密保存）</td><br>    </tr><br><br>    <tr><br>        <td>特点</td><br>        <td>内容量少，体积更小，适合快速装载，可用于全文搜索</td><br>        <td>内容详细，点击卡片后展示，用于详情页显示</td><br>    </tr><br><br>    <tr><br>        <td>包含对象</td><br>        <td>1. 标题<br>2. 摘要<br>3. 头像<br>4.标识码</td><br>        <td>1. 标题<br>2. 用户名（帐号）<br>3. 密码<br>4. Url<br>5. 备注<br>6. 头像及背景<br>7. 扩展信息（绑定关系、密保信息、二级密码、用户昵称等）<br>8. 自动生成的信息等<br>9.标识码</td><br>    </tr><br><br>    <tr><br>        <td>什么是标识码？</td><br>        <td colspan="2">每个card与useritem通过标识码建立唯一联系。<br>标识码的生成规则（暂定）：标题（String）+账号等级（int）（示意图如下）<br><img src="http://ozurciydg.bkt.clouddn.com/17-12-3/44311689.jpg" alt="标识码示意图"><br>这个账号管理布局是通过点击右分页的“@id/userLink”按钮打开的</td><br>    </tr><br><br></table>

<p>本章只讲cardList的绑定和加载，UserItem会在之后的学习中补上。</p>
<h1 id="4-运行测试"><a href="#4-运行测试" class="headerlink" title="4. 运行测试"></a>4. 运行测试</h1><p>为了测试我们的数据保存是否成功，我们需要完成以下功能：</p>
<ol>
<li>退出时加密保存当前数据到“/data/data/com.likianta.anykey/my_prefs/card_data.xml”（这里用一个test按钮实现）</li>
<li>再次启动app，进入主界面后，需要从本地（card_data.xml）取出卡片数据</li>
</ol>
<p>具体代码如下：</p>
<p><font>1. 在<code>activity_main.xml</code>中添加一个测试按钮：</font></p>
<p><img src="http://ozurciydg.bkt.clouddn.com/17-12-3/77953561.jpg" alt=""></p>
<p><code>activity_main.xml</code></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">RelativeLayout</span> <span class="attr">...</span>&gt;</span></span><br><span class="line">    </span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">Button</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:id</span>=<span class="string">"@+id/test_save"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_width</span>=<span class="string">"wrap_content"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_height</span>=<span class="string">"wrap_content"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:text</span>=<span class="string">"test save"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_alignParentTop</span>=<span class="string">"true"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_alignParentStart</span>=<span class="string">"true"</span>/&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">RelativeLayout</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p><font>2. 在<code>MainActivity.java</code>中添加相关业务：</font></p>
<p><code>MainActivity.java</code></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MainActivity</span> <span class="keyword">extends</span> <span class="title">AppCompatActivity</span> <span class="keyword">implements</span> <span class="title">View</span>.<span class="title">OnClickListener</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onCreate</span><span class="params">(Bundle savedInstanceState)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        ...</span><br><span class="line"></span><br><span class="line">        <span class="comment">//test save</span></span><br><span class="line">        Button button = (Button)findViewById(R.id.test_save);</span><br><span class="line">        button.setOnClickListener(<span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//为分页加载卡片列表</span></span><br><span class="line">        PageRender();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onClick</span><span class="params">(View view)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">switch</span> (view.getId()) &#123;</span><br><span class="line"></span><br><span class="line">            ...</span><br><span class="line"></span><br><span class="line">            <span class="keyword">case</span> R.id.test_save:    </span><br><span class="line">                <span class="keyword">new</span> SavedToMySharedPrefs(MainActivity.<span class="keyword">this</span>,<span class="string">"card_data"</span>).setCardData(cardList);</span><br><span class="line">                MainActivity.<span class="keyword">this</span>.finish();</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//渲染分页（即加载卡片列表）</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">PageRender</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        </span><br><span class="line">        cardList = <span class="keyword">new</span> SavedToMySharedPrefs(MainActivity.<span class="keyword">this</span>,<span class="string">"card_data"</span>).getCardData(); <span class="comment">//从本地文件加载卡片数据</span></span><br><span class="line">        </span><br><span class="line">        cardAdapter = <span class="keyword">new</span> CardAdapter(cardList); <span class="comment">//将数组数据适配为卡片数据</span></span><br><span class="line">        recyclerView1 = (RecyclerView) page1.findViewById(R.id.recyclerView);</span><br><span class="line">        recyclerView1.setLayoutManager(<span class="keyword">new</span> LinearLayoutManager(<span class="keyword">this</span>)); <span class="comment">//为recyclerView设置线性布局，使内部元素呈线性排列</span></span><br><span class="line">        recyclerView1.setAdapter(cardAdapter); <span class="comment">//开始加载卡片</span></span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>为了保证测试能够成功，先把手机（或者模拟器）上的app给卸载掉。<br>然后启动调试：</p>
<p><img src="http://ozurciydg.bkt.clouddn.com/17-12-3/88634701.jpg" alt=""></p>
<p><br></p>
<p>至此，本章的主要内容已经讲完了。<br>本章的代码虽然特别多，但主要只做了两件事：一个是通过SecuritySharedPreference重新完成了登录的流程；另一个则是成功实现了卡片数据的保存以及卡片列表的加载更新。<br>当然我们还有很多必要的事情没有去做，比如删除卡片、点击保存按钮要把当前表单清空、以及最容易被人忽略的布局优化。  </p>
<p>随着项目逐渐变大，对于内存的要求也开始增加。此时可能已经出现使用真机调试会发生OOM（Out<br>of Memory）的崩溃，下面在更新章节5.2.中提到的办法会在一定程度上避免OOM的问题（不同手机可能遇到的状况不同。我的红米Note2手机经过下面的修改在调试时已经不崩溃了）。之后我们会一边继续完善当前的代码，一边严格控制运行消耗，特别是图像加载导致的oom问题需要多加注意。</p>
<p>在接下来的章节中将开始制作分组列表、底部导航按钮以及优化右分页布局，以减轻GPU渲染压力。</p>
<hr>
<h1 id="5-更新修复"><a href="#5-更新修复" class="headerlink" title="5. 更新修复"></a>5. 更新修复</h1><h2 id="5-1-一些小的更新修复"><a href="#5-1-一些小的更新修复" class="headerlink" title="5.1. 一些小的更新修复"></a>5.1. 一些小的更新修复</h2><p><font>1. card布局微调</font></p>
<p>主要修改了距离属性。整体代码如下：</p>
<p><code>card.xml</code></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version="1.0" encoding="utf-8"?&gt;</span><br><span class="line"><span class="tag">&lt;<span class="name">android.support.v7.widget.CardView</span> <span class="attr">xmlns:android</span>=<span class="string">"http://schemas.android.com/apk/res/android"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:app</span>=<span class="string">"http://schemas.android.com/apk/res-auto"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:tools</span>=<span class="string">"http://schemas.android.com/tools"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_width</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_height</span>=<span class="string">"120dp"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:layout_margin</span>=<span class="string">"5dp"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">android:elevation</span>=<span class="string">"4dp"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">app:cardCornerRadius</span>=<span class="string">"8dp"</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--elevation表示卡片的高度</span></span><br><span class="line"><span class="comment">     cardCornerRadius表示卡片四个角的弧度</span></span><br><span class="line"><span class="comment">     xmlns:tools用于识别TextView中的\n换行符--&gt;</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">&lt;!--CardView本身是一个FrameLayout，显然不适合摆放控件。</span></span><br><span class="line"><span class="comment">     因此为了充分利用空间，要内建一个RelativeLayout来盛放子控件--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">RelativeLayout</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_width</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:layout_height</span>=<span class="string">"match_parent"</span>&gt;</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">&lt;!--首先思路就是把RelativeLayout分为左中右三个部分，左边贴一个头像；中间占的面积最大，用来写标题和摘要；右边则放置功能按钮--&gt;</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">&lt;!--现在写的是中间的布局LinearLayout。在LinearLayout中上半部分显示标题，下半部分显示摘要--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">LinearLayout</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_width</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_height</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_marginEnd</span>=<span class="string">"40dp"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_marginStart</span>=<span class="string">"80dp"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:orientation</span>=<span class="string">"vertical"</span>&gt;</span></span><br><span class="line">            <span class="comment">&lt;!--注意设定LinearLayout的方向为vertical--&gt;</span></span><br><span class="line">            </span><br><span class="line">            <span class="comment">&lt;!--标题，深色，字号较大，高度比重为40%--&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">TextView</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:id</span>=<span class="string">"@+id/cardTitle"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_width</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_height</span>=<span class="string">"0dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_weight</span>=<span class="string">"4"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:gravity</span>=<span class="string">"bottom"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:padding</span>=<span class="string">"4dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:text</span>=<span class="string">"TitleTest"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:textColor</span>=<span class="string">"@color/mycolorText1"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:textSize</span>=<span class="string">"32sp"</span> /&gt;</span></span><br><span class="line">            </span><br><span class="line">            <span class="comment">&lt;!--摘要，浅色或同色，字号比正常文字还要小，高度比重为60%，限制显示三行文字--&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">TextView</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:id</span>=<span class="string">"@+id/cardSummary"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_width</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_height</span>=<span class="string">"0dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_weight</span>=<span class="string">"6"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:ellipsize</span>=<span class="string">"end"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:lines</span>=<span class="string">"3"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:maxLines</span>=<span class="string">"3"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:text</span>=<span class="string">"name: ______\npassword: ______\nnote: this view limited 3 lines"</span> /&gt;</span></span><br><span class="line">            <span class="comment">&lt;!--maxLines表示最大行数，lines表示即使只有一行字也要占用三行字的高度空间，ellipsize表示多出的字数表示为省略号</span></span><br><span class="line"><span class="comment">            参考：http://blog.csdn.net/qq_31403303/article/details/51506524--&gt;</span></span><br><span class="line">        </span><br><span class="line">        <span class="tag">&lt;/<span class="name">LinearLayout</span>&gt;</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">&lt;!--接下来写的是右边的布局，也是LinearLayout布局。从上到下依次显示三个按钮：菜单、复制name、复制password--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">LinearLayout</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_width</span>=<span class="string">"40dp"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_height</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_alignParentEnd</span>=<span class="string">"true"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:orientation</span>=<span class="string">"vertical"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:padding</span>=<span class="string">"5dp"</span>&gt;</span></span><br><span class="line">            </span><br><span class="line">            <span class="comment">&lt;!--菜单按钮--&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">ImageView</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:id</span>=<span class="string">"@+id/cardMenu"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_width</span>=<span class="string">"32dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_height</span>=<span class="string">"32dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:src</span>=<span class="string">"@drawable/icon_more"</span> /&gt;</span></span><br><span class="line">    </span><br><span class="line">            <span class="comment">&lt;!-- 复制用户名按钮 --&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">ImageView</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:id</span>=<span class="string">"@+id/copyName"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_width</span>=<span class="string">"14dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_height</span>=<span class="string">"14dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_gravity</span>=<span class="string">"center"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_marginTop</span>=<span class="string">"22dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:src</span>=<span class="string">"@drawable/shape_oval1"</span> /&gt;</span></span><br><span class="line">    </span><br><span class="line">            <span class="comment">&lt;!-- 复制密码按钮 --&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">ImageView</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:id</span>=<span class="string">"@+id/copyPassword"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_width</span>=<span class="string">"14dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_height</span>=<span class="string">"14dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_gravity</span>=<span class="string">"center"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:layout_marginTop</span>=<span class="string">"16dp"</span></span></span><br><span class="line"><span class="tag">                <span class="attr">android:src</span>=<span class="string">"@drawable/shape_oval1"</span> /&gt;</span></span><br><span class="line">        </span><br><span class="line">        <span class="tag">&lt;/<span class="name">LinearLayout</span>&gt;</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">&lt;!--不要忘了左边部分。之所以留待最后才写，是为了让头像以及分割线最后加载，这样就处于其它二者的上方了--&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--先做分割线，非常细，非均等分割（上窄下宽）--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">TextView</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_width</span>=<span class="string">"match_parent"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_height</span>=<span class="string">"0.4dp"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_marginTop</span>=<span class="string">"44dp"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:background</span>=<span class="string">"#000000"</span> /&gt;</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">&lt;!--头像--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">de.hdodenhof.circleimageview.CircleImageView</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:id</span>=<span class="string">"@+id/cardHead"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_width</span>=<span class="string">"60dp"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_height</span>=<span class="string">"60dp"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_marginStart</span>=<span class="string">"10dp"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:layout_marginTop</span>=<span class="string">"16dp"</span></span></span><br><span class="line"><span class="tag">            <span class="attr">android:src</span>=<span class="string">"@color/mycolorText2"</span> /&gt;</span></span><br><span class="line">    </span><br><span class="line">    <span class="tag">&lt;/<span class="name">RelativeLayout</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">android.support.v7.widget.CardView</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p><font>2. 更新build.gradle库版本到最新</font></p>
<p>更新方式很简单：将鼠标移到compile代码上，AS会检测并提示“A newer version of … is available:25.4.0 …”（如图所示），只要把“available”后面的版本填上去，再点击“Sync Now”即可同步到最新。</p>
<p><img src="http://ozurciydg.bkt.clouddn.com/17-12-3/46262616.jpg" alt=""></p>
<h2 id="5-2-OOM（内存溢出）问题的临时解决方案"><a href="#5-2-OOM（内存溢出）问题的临时解决方案" class="headerlink" title="5.2. OOM（内存溢出）问题的临时解决方案"></a>5.2. OOM（内存溢出）问题的临时解决方案</h2><p>由于在真机调试时发现应用一进入就发生oom崩溃，可以采取以下方法来暂时解决该问题：</p>
<p>在<code>AndroidManifest.xml</code>中添加一行代码：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">manifest</span> <span class="attr">...</span>&gt;</span></span><br><span class="line">    </span><br><span class="line">    <span class="tag">&lt;<span class="name">application</span></span></span><br><span class="line"><span class="tag">        <span class="attr">android:largeHeap</span>=<span class="string">"true"</span></span></span><br><span class="line"><span class="tag">        <span class="attr">...</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">application</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">manifest</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>虽然解决了一打开就崩溃的问题，但真正问题还是没有得到解决：<br>当我们左右滑动页面的时候，会发现滑动到右分页掉帧严重，这是因为GPU压力过大造成的，只能通过优化布局和图像加载来真正地解决。</p>
<p>在下章中将详细介绍如何通过优化右分页布局来解决此问题。</p>
<hr>
<h1 id="相关参考"><a href="#相关参考" class="headerlink" title="相关参考"></a>相关参考</h1><ol>
<li>LitePal：郭霖《第一行代码 第二版》p229</li>
<li><strong>LogUtil：郭霖《第一行代码 第二版》p464</strong></li>
<li>android 怎么获取字符串中指定的字符_百度知道 <a href="https://zhidao.baidu.com/question/456088699070757285.html" target="_blank" rel="noopener">https://zhidao.baidu.com/question/456088699070757285.html</a></li>
<li>可动态显示圆形图像或圆形文字的AvatarImageView - Carbs的博客 - CSDN博客 <a href="http://blog.csdn.net/yeah0126/article/details/51543830" target="_blank" rel="noopener">http://blog.csdn.net/yeah0126/article/details/51543830</a></li>
<li><strong>hdodenhof/CircleImageView: A circular ImageView for Android <a href="https://github.com/hdodenhof/CircleImageView" target="_blank" rel="noopener">https://github.com/hdodenhof/CircleImageView</a> </strong></li>
<li>ImageView的scaleType设置不当，导致使用Glide时出现OOM - 泡在网上的日子 <a href="http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0606/3002.html" target="_blank" rel="noopener">http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0606/3002.html</a></li>
<li>ImageView.ScaleType设置图解 - CSDN博客 <a href="http://blog.csdn.net/larryl2003/article/details/6919513" target="_blank" rel="noopener">http://blog.csdn.net/larryl2003/article/details/6919513</a></li>
<li>ImageView的src和background的区别、padding的使用技巧、ImageView根据屏幕对缩放 - CSDN博客 <a href="http://blog.csdn.net/u010566681/article/details/70899220" target="_blank" rel="noopener">http://blog.csdn.net/u010566681/article/details/70899220</a></li>
<li><strong>Glide使用详解（一） - CSDN博客 <a href="http://blog.csdn.net/shangmingchao/article/details/51125554/" target="_blank" rel="noopener">http://blog.csdn.net/shangmingchao/article/details/51125554/</a> </strong></li>
<li>Android RecyclerView横向滑动 - CSDN博客 <a href="http://blog.csdn.net/kingcruel/article/details/50763186" target="_blank" rel="noopener">http://blog.csdn.net/kingcruel/article/details/50763186</a></li>
<li><strong>Android框架之路——Glide加载图片（结合RecyclerView、CardView） - CSDN博客 <a href="http://blog.csdn.net/bskfnvjtlyzmv867/article/details/71106123" target="_blank" rel="noopener">http://blog.csdn.net/bskfnvjtlyzmv867/article/details/71106123</a> </strong></li>
<li>iamMehedi/Secured-Preference-Store: <a href="https://github.com/iamMehedi/Secured-Preference-Store" target="_blank" rel="noopener">https://github.com/iamMehedi/Secured-Preference-Store</a></li>
<li><strong>SharedPreferences保存List和对象序列化数据 - jxf_access的专栏 - CSDN博客 <a href="http://m.blog.csdn.net/jxf_access/article/details/61199519" target="_blank" rel="noopener">http://m.blog.csdn.net/jxf_access/article/details/61199519</a> </strong></li>
<li><strong>【Android安全】自带加密光环的SharedPreference - CSDN博客 <a href="http://blog.csdn.net/voidmain_123/article/details/53338393" target="_blank" rel="noopener">http://blog.csdn.net/voidmain_123/article/details/53338393</a> </strong></li>
<li>Gitbook/Markdown中插入复杂（合并单元格）的表格 - 一个Technical Writer的博客 - CSDN博客 <a href="http://blog.csdn.net/wiborgite/article/details/78044656" target="_blank" rel="noopener">http://blog.csdn.net/wiborgite/article/details/78044656</a></li>
</ol>
<hr>
<h1 id="日志"><a href="#日志" class="headerlink" title="日志"></a>日志</h1><p><strong>2017年11月30日</strong></p>
<ol>
<li><strong>【更新】采用LogUtil管理日志</strong></li>
<li>【更新】整理代码中注释</li>
<li>【删除】不再使用LitePal，转用SharedPreferences</li>
<li>【修改】削减标题栏的文字可点击区域</li>
<li>【修改】card.xml上的小按钮改用ImageView</li>
<li><strong>【新增】使用SecurePreferenceStore加/解密</strong></li>
<li>【修改】首次使用时登录界面的初始值的判断</li>
<li>【新增】完成登录的加密解密过程</li>
</ol>
<p><strong>2017年12月2日</strong></p>
<ol>
<li><strong>【更新】解决真机调试时的oom问题</strong></li>
<li>【修改】右分页中的HorizontalScrollView改为横向RecyclerView</li>
<li>【删除】右分页保存按钮的selector背景和文字颜色</li>
<li><strong>【新增】Glide库</strong></li>
<li><strong>【更新】使用SecuritySharedPreference加密</strong></li>
<li>【新增】SavedToMySharedPrefs类用于本地存取</li>
<li>【更新】剔除不需要的java类（SqliteDB、OpenHelper等）</li>
</ol>
</font></font></font></font></font>
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      
      
        <div class="post-widgets">
        

        

        
          
          <div id="needsharebutton-postbottom">
            <span class="btn">
              <i class="fa fa-share-alt" aria-hidden="true"></i>
            </span>
          </div>
        
        </div>
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2017/1203142827/" rel="next" title="为你的Android Studio更换主题风格">
                <i class="fa fa-chevron-left"></i> 为你的Android Studio更换主题风格
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2017/1211202828/" rel="prev" title="07 Anykey图像优化及文字头像生成与加载">
                07 Anykey图像优化及文字头像生成与加载 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          

  
    <div class="comments" id="comments">
      <div id="lv-container" data-id="city" data-uid="MTAyMC8zNDI4MS8xMDgxOA=="></div>
    </div>

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <img class="site-author-image" itemprop="image"
                src="http://ozurciydg.bkt.clouddn.com/18-2-12/72826549.jpg"
                alt="Likianta" />
            
              <p class="site-author-name" itemprop="name">Likianta</p>
              <p class="site-description motion-element" itemprop="description">Android Dev</p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/archives/">
              
                  <span class="site-state-item-count">73</span>
                  <span class="site-state-item-name">日志</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-categories">
                <a href="/categories/index.html">
                  <span class="site-state-item-count">8</span>
                  <span class="site-state-item-name">分类</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-tags">
                <a href="/tags/index.html">
                  <span class="site-state-item-count">2</span>
                  <span class="site-state-item-name">标签</span>
                </a>
              </div>
            

          </nav>

          
            <div class="feed-link motion-element">
              <a href="/atom.xml" rel="alternate">
                <i class="fa fa-rss"></i>
                RSS
              </a>
            </div>
          

          
            <div class="links-of-author motion-element">
                
                  <span class="links-of-author-item">
                    <a href="http://blog.csdn.net/likianta" target="_blank" title="CSDN">
                      
                        <i class="fa fa-fw fa-crosshairs"></i>CSDN</a>
                  </span>
                
                  <span class="links-of-author-item">
                    <a href="mailto:sheerish@qq.com" target="_blank" title="E-Mail">
                      
                        <i class="fa fa-fw fa-envelope"></i>E-Mail</a>
                  </span>
                
                  <span class="links-of-author-item">
                    <a href="https://github.com/likianta" target="_blank" title="GitHub">
                      
                        <i class="fa fa-fw fa-github"></i>GitHub</a>
                  </span>
                
                  <span class="links-of-author-item">
                    <a href="https://weibo.com/5441767757/profile?rightmod=1&wvr=6&mod=personinfo" target="_blank" title="Weibo">
                      
                        <i class="fa fa-fw fa-weibo"></i>Weibo</a>
                  </span>
                
            </div>
          

          
          

          
          

          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#1-预先准备"><span class="nav-text">1. 预先准备</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-1-先看一下最终效果图"><span class="nav-text">1.1. 先看一下最终效果图</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#1-2-确认默认启动界面仍是登录界面"><span class="nav-text">1.2. 确认默认启动界面仍是登录界面</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#1-3-创建LogUtil-java用来记录日志"><span class="nav-text">1.3. 创建LogUtil.java用来记录日志</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#1-4-添加以下依赖库"><span class="nav-text">1.4. 添加以下依赖库</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#2-使用SecuritySharedPreference完成登录的加-解密过程"><span class="nav-text">2. 使用SecuritySharedPreference完成登录的加/解密过程</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#2-1-配置SecuritySharedPreference"><span class="nav-text">2.1. 配置SecuritySharedPreference</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#4-运行测试"><span class="nav-text">4. 运行测试</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#5-更新修复"><span class="nav-text">5. 更新修复</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#5-1-一些小的更新修复"><span class="nav-text">5.1. 一些小的更新修复</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#5-2-OOM（内存溢出）问题的临时解决方案"><span class="nav-text">5.2. OOM（内存溢出）问题的临时解决方案</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#相关参考"><span class="nav-text">相关参考</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#日志"><span class="nav-text">日志</span></a></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <script async src="//dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<div class="copyright">&copy; 2017 &mdash; <span itemprop="copyrightYear">2018</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Likianta</span>

  
</div>


  <div class="powered-by">
    <i class="fa fa-user-md"></i>
    <span id="busuanzi_container_site_pv">
      Site visitors:<span id="busuanzi_value_site_pv"></span>
    </span>
  </div>

<!--
  <div class="powered-by">由 <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a> 强力驱动</div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">主题 &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Mist</a> v5.1.3</div>

-->



<div class="theme-info">
  <div class="powered-by"></div>
  <span class="post-count">Site words total count:75.2k</span>
</div>
        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.3"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.3"></script>



  
  

  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.3"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.3"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.3"></script>



  


  




	





  





  
    <script type="text/javascript">
      (function(d, s) {
        var j, e = d.getElementsByTagName(s)[0];
        if (typeof LivereTower === 'function') { return; }
        j = d.createElement(s);
        j.src = 'https://cdn-city.livere.com/js/embed.dist.js';
        j.async = true;
        e.parentNode.insertBefore(j, e);
      })(document, 'script');
    </script>
  












  





  

  

  

  
  
  
  <link rel="stylesheet" href="/lib/needsharebutton/needsharebutton.css">

  
  
  <script src="/lib/needsharebutton/needsharebutton.js"></script>

  <script>
    
      pbOptions = {};
      
          pbOptions.iconStyle = "box";
      
          pbOptions.boxForm = "horizontal";
      
          pbOptions.position = "bottomCenter";
      
          pbOptions.networks = "Weibo,Wechat,Douban,QQZone,Evernote";
      
      new needShareButton('#needsharebutton-postbottom', pbOptions);
    
    
  </script>

  

  

  

  

</body>
</html>
